import ProductAPI from '@/api/Product';
import ProductRelationAPI from '@/api/ProductRelation';
import {
  Box,
  concatName,
  FieldCols,
  FieldEffect,
  FieldTable,
  FormSection,
  mapField,
  ModalSelectTable,
  useCall,
  useFieldName,
  useFormValue,
  usePubSub,
  usePubSubState,
  useQueryValues,
  useReq,
  useSimpleMemo,
  useWillMountEffect,
} from '@/components';
import { ADDITION_RISK_TYPE, MAIN_RISK_TYPE, PRODUCT_TYPE_INSURE, TIME_RISK_MARK } from '@/constants/options';
import { enumToOptions, pick } from '@/utils';
import { catchAndScrollFor } from '@/utils/fp';
import { Button, Form, message, Select, Space, Spin } from 'antd';
import React, { createContext, useContext, useEffect, useMemo } from 'react';

const Context = createContext({ businessCode: null, productType: null });

const MAIN_FIELDS = [
  ['businessCode', '业务编码', null, { readOnly: true }],
  ['productCode', '险种编码', null, { readOnly: true }],
  ['productName', '险种名称', null, { readOnly: true }],
  ['companyName', '保险公司', null, { readOnly: true }],
  ['productCategory', '险种分类', 'dict', { open: false, code: 'agency' }],
  ['timeRiskMark', '长短险类型', 'select', { open: false, options: enumToOptions(TIME_RISK_MARK) }],
  ['productType', '主附险类型', 'select', { open: false, options: enumToOptions(PRODUCT_TYPE_INSURE) }],
].map(mapField);

const relationTypes = {
  addition: '0', // 附加
  bind: '1', // 捆绑
  mutex: '2', // 互斥
};

const roleMarkMap = {
  0: '主动方',
  1: '被动方',
};

const roleMark = {
  aggressive: '0',
  passive: '1',
};

function useIsAdditionRisk() {
  return useContext(Context).productType !== MAIN_RISK_TYPE;
}

function RelationSelect(props) {
  const isAdditionRisk = useIsAdditionRisk();
  const pubsub = usePubSub();
  const itemProductType = usePubSubState(pubsub);
  const isAdditionItem = itemProductType !== MAIN_RISK_TYPE;
  const fieldName = useFieldName();
  const typeName = useSimpleMemo(concatName(fieldName, ['../', 'productType']));

  const addToAdd = [
    { value: '1', label: '捆绑' },
    { value: '2', label: '互斥' },
  ];
  const addToRisk = [{ value: '0', label: '被附加' }];
  const riskToAdd = [{ value: '0', label: '可附加' }];
  const options = useSimpleMemo(isAdditionRisk ? (isAdditionItem ? addToAdd : addToRisk) : riskToAdd);

  return (
    <>
      <FieldEffect name={typeName} pubsub={pubsub} />
      <Select {...props} options={options} />
    </>
  );
}

const RELATION_FIELDS = [
  ['businessCode', '业务编码', 'plain', { width: 160 }],
  ['productCode', '险种编码', 'plain', { width: 160 }],
  ['productName', '险种名称', 'plain', { required: true }],
  ['relation', '关系', RelationSelect, { width: '15%', required: true }],
  [
    'roleMark',
    '角色',
    'select',
    {
      width: '15%',
      align: 'center',
      options: enumToOptions(roleMarkMap),
      open: false,
      bordered: false,
      showArrow: false,
    },
  ],
].map(mapField);

function RelationList() {
  const { form, businessCode } = useContext(Context);
  const companyCode = useFormValue(form, 'companyCode');
  const isAdditionRisk = useIsAdditionRisk();
  const selectedKeys = useFormValue(form, 'list', (v) => v?.map((t) => t.businessCode) ?? []);

  const onAdd = useCall((list) => {
    const prevList = form.getFieldValue('list');
    console.log(list, prevList);
    const prevCodeList = prevList.map((v) => v.businessCode);
    let newList = list;
    // newList = newList.filter((v) => !prevCodeList.includes(v.businessCode));
    newList = newList.map((v) => ({
      productType: v.productType,
      businessCode: v.businessCode,
      productCode: v.productCode,
      productName: v.productName,
      roleMark: v.productType !== MAIN_RISK_TYPE ? roleMark.passive : roleMark.aggressive,
      relation: isAdditionRisk ? (v.productType !== MAIN_RISK_TYPE ? '1' : '0') : '0',
    }));

    // form.setFieldsValue({ list: prevList.concat(newList) });
    form.setFieldsValue({ list: newList });
  });

  // 附加险可查看所有，主险只能查询附加险
  const onProductService = useCall((formData) => [
    {
      ...formData,
      productType: isAdditionRisk ? '' : ADDITION_RISK_TYPE,
      companyCode,
    },
  ]);

  const selectFields = useMemo(
    () =>
      [
        ['businessCode', '业务编码'],
        ['productCode', '险种编码'],
        ['productName', '险种名称'],
        ['productCategory', '险种分类', 'dict', { code: 'agency', hides: [''] }],
      ].map(mapField),
    [],
  );

  const selectColumns = useMemo(
    () => [
      { dataIndex: 'businessCode', title: '业务编码', width: 140 },
      { dataIndex: 'productCode', title: '险种编码', width: 140 },
      { dataIndex: 'companyName', title: '保险公司', width: 110, ellipsis: true },
      { dataIndex: 'productName', title: '险种名称', minWidth: 100 },
      { dataIndex: 'productCategory', title: '险种分类', dict: 'agency', width: 80 },
      { dataIndex: 'productType', title: '主附险类型', map: PRODUCT_TYPE_INSURE, width: 120 },
    ],
    [],
  );

  return (
    <>
      <Box>
        <ModalSelectTable
          title='选择险种'
          service={ProductAPI.selectAll}
          fields={selectFields}
          columns={selectColumns}
          onResult={(result) => (result?.data ?? []).filter((r) => r.businessCode !== businessCode)}
          selectedKeys={selectedKeys}
          onOk={onAdd}
          selectType='checkbox'
          rowKey='businessCode'
          onService={onProductService}
        >
          <Button type='primary'>新增</Button>
        </ModalSelectTable>
        <Box py={2} />
      </Box>
      <FieldTable form={form} name='list' showRemoveBtn fields={RELATION_FIELDS} />
    </>
  );
}

const getItem = (item) => pick(item, ['businessCode', 'productCode', 'productName'])[0];

const form2data = (formData, allRelation, optionalRelation) => {
  const data = JSON.parse(JSON.stringify(formData));
  const { businessCode, productCode, productName, productType, list } = data;
  const self = (data = null) => ({ ...data, businessCode, productCode, productName });

  let saveAllRelation = null;
  let saveOptionalRelation = null;
  if (productType === MAIN_RISK_TYPE) {
    saveOptionalRelation = {
      id: optionalRelation?.id,
      businessCode,
      productCode,
      productName,
      child: list.map(getItem),
    };
  } else {
    const productBinding = {
      id: allRelation?.productBinding?.id,
      businessCode,
      productCode,
      productName,
      child: [],
    };
    const productOptional = {
      id: allRelation?.productOptional?.id,
      businessCode,
      productCode,
      productName,
      child: [],
    };

    const productMutexs = [];

    const mutexIdByCode = {};

    if (allRelation) {
      allRelation.productMutexs?.forEach((prevMutex) => {
        const { businessCode } = prevMutex.child.find((v) => v.businessCode !== prevMutex.businessCode);
        mutexIdByCode[businessCode] = prevMutex.id;
      });
    }

    list.forEach((item) => {
      const { businessCode } = item;
      switch (item.relation) {
        case relationTypes.addition:
          productOptional.child.push(getItem(item));
          break;

        case relationTypes.bind:
          if (productBinding.child.every((v) => v.businessCode !== businessCode)) {
            productBinding.child.push(getItem(item));
          }
          break;

        case relationTypes.mutex:
          if (productMutexs.every((v) => !v.child.find((v) => v.businessCode === businessCode))) {
            productMutexs.push(
              self({
                id: mutexIdByCode[businessCode],
                child: [self(), getItem(item)],
              }),
            );
          }
          delete mutexIdByCode[businessCode];
          break;
      }
    });

    Object.keys(mutexIdByCode).forEach((prevMutexCode) => {
      productMutexs.push(self({ id: mutexIdByCode[prevMutexCode], child: [] }));
    });

    if (productBinding.child.length) {
      productBinding.child.push(self());
    }

    saveAllRelation = { productBinding, productMutexs, productOptional };
  }

  return [saveAllRelation, saveOptionalRelation];
};

const data2form = (riskData, allRelation, optionalRelation) => {
  const riskFormData = pick(riskData, [
    'productType',
    'businessCode',
    'productCode',
    'productName',
    'productCategory',
    'timeRiskMark',
  ])[0];
  const { productType, businessCode } = riskFormData;
  let list = [];
  if (productType === MAIN_RISK_TYPE) {
    list =
      optionalRelation?.child?.map((i) => ({
        relation: relationTypes.addition,
        productType: ADDITION_RISK_TYPE,
        ...getItem(i),
      })) ?? [];
  } else {
    allRelation?.productOptional?.child?.forEach((item) => {
      if (item.businessCode !== businessCode) {
        list.push({
          productType: MAIN_RISK_TYPE,
          relation: relationTypes.addition,
          ...getItem(item),
        });
      }
    });

    allRelation?.productBinding?.child.forEach((item) => {
      if (item.businessCode !== businessCode) {
        list.push({
          productType: ADDITION_RISK_TYPE,
          relation: relationTypes.bind,
          ...getItem(item),
        });
      }
    });

    allRelation?.productMutexs?.forEach((item) => {
      list.push({
        productType: MAIN_RISK_TYPE,
        relationId: item.id,
        relation: relationTypes.mutex,
        ...getItem(item.child.find((v) => v.businessCode !== businessCode)),
      });
    });
  }

  return { ...riskFormData, list };
};

function AddPage({ history }) {
  const [businessCode, productType] = useQueryValues('businessCode', 'productType');
  const saveXhr = useReq(ProductRelationAPI.insertOrUpdate);
  const saveAllRelation = useReq(ProductRelationAPI.saveAllRelation);
  const getAllRelation = useReq(ProductRelationAPI.getAllRelation);
  const getOptionalRelation = useReq(ProductRelationAPI.getOptionalRelation);
  const saveOptionalRelation = useReq(ProductRelationAPI.saveOptionalRelation);
  const [form] = Form.useForm();

  const productData = useMemo(() => JSON.parse(sessionStorage.getItem('relationEditItem')), []);
  useWillMountEffect(() => {
    form.setFieldsValue(productData);
  });

  useEffect(() => {
    if (businessCode) {
      Promise.all([
        productType !== MAIN_RISK_TYPE && getAllRelation.start(businessCode),
        productType === MAIN_RISK_TYPE && getOptionalRelation.start(businessCode),
      ]).then(([allRelation, optionalRelation]) => {
        form.setFieldsValue(data2form(productData, allRelation?.data, optionalRelation?.data));
      });
    }
  }, [businessCode]);

  const handleSave = useCall(async () => {
    const values = await form.validateFields().catch(catchAndScrollFor(form));
    const [allRelation, optionalRelation] = form2data(
      values,
      getAllRelation.result?.data,
      getOptionalRelation.result?.data,
    );
    if (allRelation) await saveAllRelation.start(allRelation);
    if (optionalRelation) await saveOptionalRelation.start(optionalRelation);
    message.success('保存成功, 停/在售管理重新上下架关联产品后修改生效', 5);
    history.goBack();
  });

  const loading = [
    saveXhr.status,
    saveAllRelation.status,
    getAllRelation.status,
    getOptionalRelation.status,
    saveOptionalRelation.status,
  ].includes('loading');

  const context = useSimpleMemo({ form, businessCode, productType });

  return (
    <Context.Provider value={context}>
      <Spin spinning={loading}>
        <Form component={false} form={form}>
          <FormSection title='险种关联'>
            <FieldCols form={form} fields={MAIN_FIELDS} />
          </FormSection>

          <Box py={1} />
          <RelationList />

          <Box flex jus='center' py={3} className='form-page-btn'>
            <Space size='large'>
              <Button onClick={history.goBack}>返回</Button>
              <Button type='primary' onClick={handleSave}>
                保存
              </Button>
            </Space>
          </Box>
        </Form>
      </Spin>
    </Context.Provider>
  );
}

export default AddPage;
